---
layout: layout.njk
permalink: "{{ page.filePathStem }}.html"
title: Smile - Quick Start
---
{% include "toc.njk" %}

<div class="col-md-9 col-md-pull-3">
    <h1 id="quickstart-top" class="title">Quick Start</h1>

    <p>Smile is a fast and comprehensive machine learning system.
        With advanced data structures and algorithms, Smile delivers the state-of-art performance.
        Smile is self-contained and requires only Java standard library.
        Since v1.4, Smile may optionally leverage native BLAS/LAPACK library too.
        It also provides high-level operators in Scala and an interactive shell.
        In practice, data scientists usually build models with high-level tools such as R, Matlab,
        SAS, etc. However, developers have to spend a lot of time and energy to incorporate these
        models in the production system that are often implemented in general purpose programming
        languages such as Java and Scala. With Smile, data scientists and developers can work
        in the same environment to build machine learning applications quickly!</p>

    <h2 id="download">Download</h2>

    <p>Get Smile from the <a href="https://github.com/haifengl/smile/releases">releases page</a> of
        the project website. The universal tarball
        is also available and can be used on Mac, Linux and Windows.</p>

    <p>If you would like to build Smile from source, please first install Java 21, Scala 2.13
        and SBT 1.0+. Then clone the repo and build the package:</p>

    <pre class="prettyprint lang-sh"><code>
    $ git clone https://github.com/haifengl/smile.git
    $ cd smile
    $ sbt package
    </code></pre>

    <p>To build with Scala 3, run</p>

    <pre class="prettyprint lang-sh"><code>
    $ sbt ++3.3.6 scala/package
    </code></pre>

    <p>To test the latest code, run the following</p>

    <pre class="prettyprint lang-sh"><code>
    $ git pull
    $ bin/smile.sh
    </code></pre>

    <p>which will build the system and enter the Smile shell in Scala.
        If you prefer Java, you may run
    </p>
    <pre class="prettyprint lang-sh"><code>
    $ sbt shell/stage
    $ cd shell/target/universal/stage
    $ bin/jshell.sh
    </code></pre>

    <h2 id="shell">Shell</h2>

    <ul class="nav nav-tabs">
        <li class="active"><a href="#java_1" data-toggle="tab">Java</a></li>
        <li><a href="#scala_1" data-toggle="tab">Scala</a></li>
        <li><a href="#kotlin_1" data-toggle="tab">Kotlin</a></li>
    </ul>
    <div class="tab-content">
        <div class="tab-pane" id="scala_1">
            <p>Smile comes with an interactive shell for Scala. In the home directory of Smile, type</p>

            <pre class="prettyprint lang-sh"><code>
    $ bin/smile
    </code></pre>

            <p>to enter the shell, which is based on Scala REPL.
                If you prefer <a href="https://ammonite.io">Ammonite REPL</a>,
                copy its jar to Smile's <code>lib</code> directory. Smile Shell
                will switch to Ammonite once restarted.
                In the shell, you can run any valid Scala expressions.
                Besides, all high-level Smile operators are predefined
                in the shell. By default, the shell uses up to 75% memory.
                If you need more memory to handle large data, use the option
                <code>-J-Xmx</code> or <code>-XX:MaxRAMPercentage</code>.
                For example,
            </p>

            <pre class="prettyprint lang-sh"><code>
    $ bin/smile -J-Xmx30G
    </code></pre>

            <p>You can also modify the configuration file <code>./conf/smile.ini</code>
                for the memory and other JVM settings.</p>

            <h3 id="basics">Basics</h3>

            <p>When the shell starts, we should see something like the following:</p>
            <pre class="prettyprint lang-scala"><code>
                                                       ..::''''::..
                                                     .;''        ``;.
     ....                                           ::    ::  ::    ::
   ,;' .;:                ()  ..:                  ::     ::  ::     ::
   ::.      ..:,:;.,:;.    .   ::   .::::.         :: .:' ::  :: `:. ::
    '''::,   ::  ::  ::  `::   ::  ;:   .::        ::  :          :  ::
  ,:';  ::;  ::  ::  ::   ::   ::  ::,::''.         :: `:.      .:' ::
  `:,,,,;;' ,;; ,;;, ;;, ,;;, ,;;, `:,,,,:'          `;..``::::''..;'
                                                       ``::,,,,::''

  Welcome to Smile Shell; enter 'help&lt;RETURN&gt;' for list of supported commands.
  Type "exit&lt;RETURN&gt;" to leave the Smile Shell
  Version 4.0.0, Scala 2.13.14, SBT 1.9.9 built at 2024-07-03 09:52:24.404-0400
===============================================================================
smile&gt;
    </code></pre>

            <p>The <strong>smile&gt;</strong> line is the prompt that the shell is waiting for you to enter expressions.
                To get help information of Smile high-level operators,
                type <code>help</code>. You can also get detailed information on
                each operator by typing <code>help("command")</code>, e.g.
                <code>help("svm")</code>. To exit the shell, type <code>exit</code>.
            </p>

            <p>In the shell, type <code>demo</code> to bring up the demo window,
                which shows off various Smile's machine learning capabilities.</p>

            <p>You can also type <code>benchmark()</code> to see Smile's performance
                on a couple of test data. You can run a particular benchmark by
                <code>bencharm("test name")</code>, where test name could be "airline",
                "usps", etc.
            </p>

            <p>On startup, the shell analyzes the classpath and creates a database of every visible package and path.
                This is available via tab-completion analogous to the path-completion available in most shells.
                If you type a partial path, tab will complete as far as it can and show you your options
                if there is more than one.</p>

            <pre class="prettyprint lang-scala"><code>
    smile&gt; smile.classification.r
    randomForest   rbfnet   rda
    </code></pre>

            <h3 id="calculator">Calculator</h3>

            <p>We can run any valid Scala expressions in the shell. In the
                simplest case, you can use it as a calculator.</p>

            <pre class="prettyprint lang-scala"><code>
    smile&gt; "Hello, World"
    res0: String = Hello, World

    smile&gt; 2
    res1: Int = 2

    smile&gt; 2+3
    res2: Int = 5
    </code></pre>

            <p>We can also define variables and reuse them.</p>

            <pre class="prettyprint lang-scala"><code>
    smile&gt; val x = 2 + 3
    x: Int = 5

    smile&gt; print(x)
    5

    smile&gt; val y = 2 * (x + 1)
    z: Int = 12
    </code></pre>

            <p>Functions can be defined too. As Scala is a functional language, functions are
                first class citizen, just like other values.</p>
            <pre class="prettyprint lang-scala"><code>
    smile&gt; def sq(x: Double) = x * x
    sq: (x: Double)Double

    smile&gt; sq(y)
    res4: Double = 441.0
    </code></pre>
            <p>Scala is a powerful and complicated language that fuses object-oriented programming and functional
                programming.
                Although you don't need to know all the bells and whistles of Scala to use Smile, we strongly recommend
                you to
                learn some <a href="https://www.scala-lang.org/documentation/">basics</a>.</p>

            <h3 id="script">Script</h3>

            <p>We may also run Smile code in a script. The script
                <code>examples/iris.sc</code> containing the following Smile code
            </p>

            <pre class="prettyprint lang-scala"><code>
    val data = read.arff(Paths.getTestData("weka/iris.arff"))
    println(data)

    val formula = "class" ~ "."
    val rf = smile.classification.randomForest(formula, data)
    println(s"OOB error = %.2f%%" format 100 * rf.error)
    </code></pre>

            <p>It can be run directly from the shell:</p>

            <pre class="prettyprint lang-sh"><code>
    $ bin/smile examples/iris.sc
    </code></pre>

            <p>In this example, we use Fisher's Iris data in the <code>data</code> directory
                (including many open data for research purpose). The data
                is in Weka's ARFF format. The function <code>read.arff</code> returns an object of
                <code>DataFrame</code>. The formula <code>"class" ~ </code> defines that
                the column "class" will be used as the class label while the rest columns
                are predictors. Finally, we train a random forest
                with default parameters and print out its OOB (out of bag) error. We can apply
                the model on new data samples with the method <code>predict</code>.
            </p>
        </div>
        <div class="tab-pane active" id="java_1">
            <p>Smile provides an integration with JShell, which is available from Java 9+.
                In the home directory of Smile, type</p>

            <pre class="prettyprint lang-sh"><code>
    $ bin/jshell.sh
    </code></pre>

            <p>to enter the JShell with Smile libraries in the class path.
                In the shell, you can run any valid Java expressions.
                In the simplest case, you can use it as a calculator.
                If you need more memory to handle large data, use the
                option <code>-R-Xmx</code>. For example,</p>

            <pre class="prettyprint lang-sh"><code>
    $ bin/jshell.sh -R-Xmx30G
    </code></pre>

            <h3 id="basics_java">Basics</h3>

            <p>When the shell starts, we should see something like the following:</p>
            <pre class="prettyprint lang-java"><code>
                                                       ..::''''::..
                                                     .;''        ``;.
     ....                                           ::    ::  ::    ::
   ,;' .;:                ()  ..:                  ::     ::  ::     ::
   ::.      ..:,:;.,:;.    .   ::   .::::.         :: .:' ::  :: `:. ::
    '''::,   ::  ::  ::  `::   ::  ;:   .::        ::  :          :  ::
  ,:';  ::;  ::  ::  ::   ::   ::  ::,::''.         :: `:.      .:' ::
  `:,,,,;;' ,;; ,;;, ;;, ,;;, ,;;, `:,,,,:'          `;..``::::''..;'
                                                       ``::,,,,::''
|  Welcome to Smile  -- Version  4.0.0
===============================================================================
|  Welcome to JShell -- Version 21.0.3
|  For an introduction type: /help intro

smile>
    </code></pre>
            <p>We pre-import Smile's definitions in JShell. To exit the shell, type <code>/exit</code>.</p>

            <h3 id="calculator_java">Calculator</h3>

            <p>With local variable type inference, it is easy to use JShell as a calculator.</p>

            <pre class="prettyprint lang-java"><code>
    smile> "Hello, World"
    $2 ==> "Hello, World"

    smile> 2
    $3 ==> 2

    smile> 2+3
    $4 ==> 5
    </code></pre>

            <p>We can also define variables and reuse them.</p>

            <pre class="prettyprint lang-java"><code>
    smile> var x = 2 + 3
    x ==> 5

    smile> var y = 2 * (x + 1)
    y ==> 12
    </code></pre>

            <h3 id="script_java">Script</h3>

            <p>We may also run Smile code in a script. The script
                <code>examples/iris.jsh</code> containing the following Smile code
            </p>

            <pre class="prettyprint lang-java"><code>
    import smile.classification.RandomForest;
    import smile.data.formula.Formula;
    import smile.io.Read;
    import smile.util.Paths;

    var data = Read.arff(Paths.getTestData("weka/iris.arff"));
    System.out.println(data);

    var formula = Formula.lhs("class");
    var rf = RandomForest.fit(formula, data);
    System.out.println(rf.metrics());
    </code></pre>

            <p>It can be run directly from the shell:</p>

            <pre class="prettyprint lang-sh"><code>
    $ bin/jshell.sh examples/iris.jsh
    </code></pre>

            <p>In this example, we use Fisher's Iris data in the <code>data</code> directory
                (including many open data for research purpose). The data
                is in Weka's ARFF format. The function <code>Read.arff</code> returns an object of
                <code>DataFrame</code>. The formula <code>Formula.lhs("class")</code> defines that
                the column "class" will be used as the class label while the rest columns
                are predictors. Finally, we train a random forest
                with default parameters and print out its OOB (out of bag) error. We can apply
                the model on new data samples with the method <code>predict</code>.
            </p>
        </div>
        <div class="tab-pane" id="kotlin_1">
            <p>Smile provides an integration with Kotlin REPL.
                In the home directory of Smile, type</p>

            <pre class="prettyprint lang-sh"><code>
    $ bin/kshell.sh
    </code></pre>

            <p>to enter the Kotlin REPL with Smile libraries in the class path.
                In the shell, you can run any valid Kotlin expressions.
                In the simplest case, you can use it as a calculator.
                If you need more memory to handle large data, use the
                option <code>-J-Xmx</code>. For example,</p>

            <pre class="prettyprint lang-sh"><code>
    $ bin/kshell.sh -J-Xmx30G
    </code></pre>

            <h3 id="basics_kotlin">Basics</h3>

            <p>When the shell starts, we should see something like the following:</p>
            <pre class="prettyprint lang-kotlin"><code>
    Welcome to Kotlin version 2.0.0 (JRE 21.0.3+7-LTS-152)
    Type :help for help, :quit for quit
    >>>
    </code></pre>
            <p>To exit the REPL, type <code>:quit</code>. Different from
                Smile Shell, we don't pre-import any Smile's definitions in Kotlin REPL.</p>

            <h3 id="calculator_kotlin">Calculator</h3>

            <p>With local variable type inference, it is easy to use JShell as a calculator.</p>

            <pre class="prettyprint lang-kotlin"><code>
    >>> "Hello, World"
    res0: kotlin.String = Hello, World
    >>> 2
    res1: kotlin.Int = 2
    >>> 2+3
    res2: kotlin.Int = 5
    </code></pre>

            <p>We can also define variables and reuse them.</p>

            <pre class="prettyprint lang-kotlin"><code>
    >>> var x = 2 + 3
    >>> var y = 2 * (x + 1)
    >>> y
    res13: kotlin.Int = 12
    </code></pre>

            <h3 id="script_kotlin">Script</h3>

            <p>We may also run Smile code in a script. The script
                <code>examples/iris.kts</code> containing the following Smile code
            </p>

            <pre class="prettyprint lang-kotlin"><code>
    import smile.*
    import smile.classification.*
    import smile.data.formula.Formula
    import smile.util.Paths

    val data = read.arff(Paths.getTestData("weka/iris.arff"))
    println(data)

    val formula = Formula.lhs("class")
    val rf = randomForest(formula, data)
    println(rf.metrics())
    </code></pre>

            <p>It can be run directly from the shell:</p>

            <pre class="prettyprint lang-sh"><code>
    $ bin/kshell.sh -Xuse-fir-lt=false -script examples/iris.kts
    </code></pre>

            <p>In this example, we use Fisher's Iris data in the <code>data</code> directory
                (including many open data for research purpose). The data
                is in Weka's ARFF format. The function <code>Read.arff</code> returns an object of
                <code>DataFrame</code>. The formula <code>Formula.lhs("class")</code> defines that
                the column "class" will be used as the class label while the rest columns
                are predictors. Finally, we train a random forest
                with default parameters and print out its OOB (out of bag) error. We can apply
                the model on new data samples with the method <code>predict</code>.
            </p>
        </div>
    </div>

    <h3 id="cli">Training and Inference CLI</h3>

    <p>A secret functionality of Smile Shell is that it can be used for training and
        inference through command line (CLI).</p>

    <ul class="nav nav-tabs">
        <li class="active"><a href="#training_1" data-toggle="tab">Training</a></li>
        <li><a href="#predict_1" data-toggle="tab">Batch Inference</a></li>
        <li><a href="#serve_1" data-toggle="tab">Online Serving</a></li>
    </ul>
    <div class="tab-content">
        <div class="tab-pane active" id="training_1">
            <div class="code" style="text-align: left;">
                <pre class="prettyprint lang-shell"><code style="white-space: preserve nowrap;">
$ bin/smile train
Smile 4.0.0
Usage: smile train [random_forest|gradient_boost|adaboost|cart|logistic|fisher|lda|qda|rda|mlp|svm|rbf|ols|lasso|ridge|elastic_net|gaussian_process] [options]

  --formula &lt;class ~ .&gt;    The model formula
  --data &lt;file&gt;            The training data file
  --test &lt;file&gt;            The optional test data file
  --model &lt;file&gt;           The model file to save
  --format &lt;csv,header=true,delimiter=\t,comment=#,escape=\,quote=&quot;&gt;
                           The data file format
  --kfold &lt;value&gt;          The k-fold cross validation
  --round &lt;value&gt;          The number of rounds of repeated cross validation
  --ensemble               Ensemble cross validation models
  --seed &lt;value&gt;           The random number generator seed
Command: random_forest [options]
Random Forest
  --regression             To train a regression model
  --trees &lt;value&gt;          The number of trees
  --mtry &lt;value&gt;           The number of features to train node split
  --split &lt;GINI, ENTROPY, CLASSIFICATION_ERROR&gt;
                           The split rule
  --max_depth &lt;value&gt;      The maximum tree depth
  --max_nodes &lt;value&gt;      The maximum number of leaf nodes
  --node_size &lt;value&gt;      The minimum leaf node size
  --sampling &lt;value&gt;       The sampling rate
  --class_weight &lt;value&gt;   The class weights
Command: gradient_boost [options]
Gradient Boosting
  --regression             To train a regression model
  --trees &lt;value&gt;          The number of trees
  --shrinkage &lt;value&gt;      The shrinkage parameter in (0, 1] controls the learning rate
  --max_depth &lt;value&gt;      The maximum tree depth
  --max_nodes &lt;value&gt;      The maximum number of leaf nodes
  --node_size &lt;value&gt;      The minimum leaf node size
  --sampling &lt;value&gt;       The sampling rate
Command: adaboost [options]
AdaBoost
  --trees &lt;value&gt;          The number of trees
  --max_depth &lt;value&gt;      The maximum tree depth
  --max_nodes &lt;value&gt;      The maximum number of leaf nodes
  --node_size &lt;value&gt;      The minimum leaf node size
Command: cart [options]
Classification and Regression Tree
  --regression             To train a regression model
  --split &lt;GINI, ENTROPY, CLASSIFICATION_ERROR>
                           The split rule
  --max_depth &lt;value&gt;      The maximum tree depth
  --max_nodes &lt;value&gt;      The maximum number of leaf nodes
  --node_size &lt;value&gt;      The minimum leaf node size
Command: logistic [options]
Logistic Regression
  --transform &lt;standardizer, winsor(0.01,0.99), minmax, MaxAbs, L1, L2, Linf&gt;
                           The feature transformation
  --lambda &lt;value&gt;         The regularization on linear weights
  --iterations &lt;value&gt;     The maximum number of iterations
  --tolerance &lt;value&gt;      The tolerance to stop iterations
Command: fisher [options]
Fisher Linear Discriminant
  --transform &lt;standardizer, winsor(0.01,0.99), minmax, MaxAbs, L1, L2, Linf&gt;
                           The feature transformation
  --dimension &lt;value&gt;      The dimensionality of mapped space
  --tolerance &lt;value&gt;      The tolerance if a covariance matrix is singular
Command: lda [options]
Linear Discriminant Analysis
  --transform &lt;standardizer, winsor(0.01,0.99), minmax, MaxAbs, L1, L2, Linf&gt;
                           The feature transformation
  --priori &lt;value&gt;         The priori probability of each class
  --tolerance &lt;value&gt;      The tolerance if a covariance matrix is singular
Command: qda [options]
Quadratic Discriminant Analysis
  --transform &lt;standardizer, winsor(0.01,0.99), minmax, MaxAbs, L1, L2, Linf&gt;
                           The feature transformation
  --priori &lt;value&gt;         The priori probability of each class
  --tolerance &lt;value&gt;      The tolerance if a covariance matrix is singular
Command: rda [options]
Regularized Discriminant Analysis
  --transform &lt;standardizer, winsor(0.01,0.99), minmax, MaxAbs, L1, L2, Linf&gt;
                           The feature transformation
  --alpha &lt;value&gt;          The regularization factor in [0, 1] allows a continuum of models between LDA and QDA
  --priori &lt;value&gt;         The priori probability of each class
  --tolerance &lt;value&gt;      The tolerance if a covariance matrix is singular
Command: mlp [options]
Multilayer Perceptron
  --regression             To train a regression model
  --transform &lt;standardizer, winsor(0.01,0.99), minmax, MaxAbs, L1, L2, Linf&gt;
                           The feature transformation
  --layers &lt;ReLU(100)|Sigmoid(30)&gt;
                           The neural network layers
  --epochs &lt;value&gt;         The number of training epochs
  --mini_batch &lt;value&gt;     The split rule
  --learning_rate &lt;0.01, linear(0.01, 10000, 0.001), piecewise(...), polynomial(...), inverse(...), exp(...)&gt;
                           The learning rate schedule
  --momentum &lt;value&gt;       The momentum schedule
  --weight_decay &lt;value&gt;   The weight decay
  --clip_norm &lt;value&gt;      The gradient clipping norm
  --clip_value &lt;value&gt;     The gradient clipping value
  --rho &lt;value&gt;            RMSProp rho
  --epsilon &lt;value&gt;        RMSProp epsilon
Command: svm [options]
Support Vector Machine
  --transform &lt;standardizer, winsor(0.01,0.99), minmax, MaxAbs, L1, L2, Linf&gt;
                           The feature transformation
  --kernel &lt;value&gt;         The kernel function
  --C &lt;value&gt;              The soft margin penalty parameter
  --epsilon &lt;value&gt;        The parameter of epsilon-insensitive hinge loss
  --ovr                    One vs Rest strategy for multiclass classification
  --ovo                    One vs One strategy for multiclass classification
  --tolerance &lt;value&gt;      The tolerance of convergence test
Command: rbf [options]
Radial Basis Function Network
  --regression             To train a regression model
  --transform &lt;standardizer, winsor(0.01,0.99), minmax, MaxAbs, L1, L2, Linf>
                           The feature transformation
  --neurons &lt;value&gt;        The number of neurons (radial basis functions)
  --normalize              Normalized RBF network
Command: ols [options]
Ordinary Least Squares
  --method &lt;qr, svd&gt;       The fitting method
  --stderr                 Compute the standard errors of the estimate of parameters.
  --recursive              Recursive least squares
Command: lasso [options]
LASSO - Least Absolute Shrinkage and Selection Operator
  --lambda &lt;value&gt;         The regularization on linear weights
  --iterations &lt;value&gt;     The maximum number of iterations
  --tolerance &lt;value&gt;      The tolerance to stop iterations (relative target duality gap)
Command: ridge [options]
Ridge Regression
  --lambda &lt;value&gt;         The regularization on linear weights
Command: elastic_net [options]
Elastic Net
  --lambda1 &lt;value&gt;        The L1 regularization on linear weights
  --lambda2 &lt;value&gt;        The L2 regularization on linear weights
  --iterations &lt;value&gt;     The maximum number of iterations
  --tolerance &lt;value&gt;      The tolerance to stop iterations (relative target duality gap)
Command: gaussian_process [options]
Gaussian Process Regression
  --transform &lt;standardizer, winsor(0.01,0.99), minmax, MaxAbs, L1, L2, Linf&gt;
                           The feature transformation
  --kernel &lt;value&gt;         The kernel function
  --noise &lt;value&gt;          The noise variance
  --normalize              Normalize the response variable
  --iterations &lt;value&gt;     The maximum number of HPO iterations
  --tolerance &lt;value&gt;      The stopping tolerance for HPO
          </code></pre>
            </div>
        </div>
        <div class="tab-pane" id="predict_1">
            <div class="code" style="text-align: left;">
                <pre class="prettyprint lang-shell"><code>
$ bin/smile predict
Smile 4.0.0
Usage: smile predict [options]

  --model &lt;value&gt;   The model file
  --data &lt;value&gt;    The data file
  --format &lt;value&gt;  The data file format/schema
  --probability     Output the posteriori probabilities for soft classifier

    </code></pre>
            </div>
        </div>
        <div class="tab-pane" id="serve_1">
            <div class="code" style="text-align: left;">
                <pre class="prettyprint lang-shell"><code>
$ bin/smile serve
Smile 4.0.0
Usage: smile serve [options]

  --model &lt;value&gt;  The model file
  --probability    Output the posteriori probabilities for soft classifier
    </code></pre>
            </div>
        </div>
    </div>

    <p>To train a model, one should specify the data file, the output model file,
        the machine learning algorithm and its hyperparameters, and the model formula.
        Once the training done, it saves the model to the specified path and
        also prints the training metrics on the console.
        If the optional test data is provided too, the validation metrics will be
        computed and displayed too.</p>

    <ul class="nav nav-tabs">
        <li class="active"><a href="#train_2" data-toggle="tab">Training</a></li>
    </ul>
    <div class="tab-content">
        <div class="tab-pane active" id="train_2">
            <div class="code" style="text-align: left;">
    <pre class="prettyprint lang-shell"><code style="white-space: preserve nowrap;">
$ bin/smile train random_forest --data data/weka/iris.arff --formula "class ~ ." --model iris_random_forest.model
[main] INFO smile.io.Arff - Read ARFF relation iris
[ForkJoinPool.commonPool-worker-3] INFO smile.classification.RandomForest - Decision tree OOB accuracy: 88.89%
[ForkJoinPool.commonPool-worker-2] INFO smile.classification.RandomForest - Decision tree OOB accuracy: 95.35%
[ForkJoinPool.commonPool-worker-1] INFO smile.classification.RandomForest - Decision tree OOB accuracy: 96.67%
...
[main] INFO smile.classification.RandomForest - Decision tree OOB accuracy: 92.73%
[ForkJoinPool.commonPool-worker-3] INFO smile.classification.RandomForest - Decision tree OOB accuracy: 94.44%
[main] INFO smile.classification.RandomForest - Decision tree OOB accuracy: 92.98%
[ForkJoinPool.commonPool-worker-3] INFO smile.classification.RandomForest - Decision tree OOB accuracy: 92.31%
[main] INFO smile.classification.RandomForest - Decision tree OOB accuracy: 95.00%
[ForkJoinPool.commonPool-worker-3] INFO smile.classification.RandomForest - Decision tree OOB accuracy: 96.30%
[main] INFO smile.classification.RandomForest - Decision tree OOB accuracy: 89.47%
[ForkJoinPool.commonPool-worker-3] INFO smile.classification.RandomForest - Decision tree OOB accuracy: 92.98%
[main] INFO smile.classification.RandomForest - Decision tree OOB accuracy: 92.45%
[ForkJoinPool.commonPool-worker-3] INFO smile.classification.RandomForest - Decision tree OOB accuracy: 96.30%
[main] INFO smile.classification.RandomForest - Decision tree OOB accuracy: 89.83%
[ForkJoinPool.commonPool-worker-3] INFO smile.classification.RandomForest - Decision tree OOB accuracy: 90.57%
[main] INFO smile.classification.RandomForest - Decision tree OOB accuracy: 94.64%
[main] INFO smile.classification.RandomForest - Decision tree OOB accuracy: 97.92%
Training metrics: {
  fit time: 191.678 ms,
  score time: 17.059 ms,
  validation data size: 150,
  error: 6,
  accuracy: 96.00%,
  cross entropy: 0.1316
}
  </code></pre>
            </div>
        </div>
    </div>

    <p>To run a batch inference on a file, run <code>smile predict</code> command
        with the model file and data file path. In this example,
        we also specify the optional flag <code>--probability</code> to compute
        the posterior probability. If you don't need it, simply skip this option.</p>

    <ul class="nav nav-tabs">
        <li class="active"><a href="#predict_2" data-toggle="tab">Batch Inference</a></li>
    </ul>
    <div class="tab-content">
        <div class="tab-pane active" id="predict_2">
            <div class="code" style="text-align: left;">
    <pre class="prettyprint lang-shell"><code>
$ bin/smile predict --model iris_random_forest.model --data data/weka/iris.arff --probability
0 0.9601 0.0205 0.0194
0 0.9599 0.0206 0.0195
0 0.9600 0.0206 0.0194
0 0.9600 0.0206 0.0194
0 0.9601 0.0205 0.0194
0 0.9586 0.0211 0.0203
0 0.9601 0.0205 0.0194
0 0.9601 0.0205 0.0194
0 0.9599 0.0206 0.0195
0 0.9600 0.0206 0.0194
0 0.9586 0.0211 0.0203
0 0.9601 0.0205 0.0194
0 0.9599 0.0206 0.0195
0 0.9599 0.0206 0.0195
0 0.9078 0.0668 0.0254
...
  </code></pre>
            </div>
        </div>
    </div>

    <p>It is also easy to create an endpoint to serve online requests.</p>
    <ul class="nav nav-tabs">
        <li class="active"><a href="#serve_2" data-toggle="tab">Online Serving</a></li>
    </ul>
    <div class="tab-content">
        <div class="tab-pane active" id="serve_2">
            <div class="code" style="text-align: left;">
    <pre class="prettyprint lang-shell"><code>
$ bin/smile serve --model iris_random_forest.model --probability --line
[smile-akka.actor.default-dispatcher-4] INFO akka.event.slf4j.Slf4jLogger - Slf4jLogger started
Smile online at http://localhost:8728/v1/infer
Press RETURN to stop...
  </code></pre>
            </div>
        </div>
    </div>

    <p>The endpoint is at <code>/v1/infer</code>. Here is an example how to make an inference request.</p>
    <ul class="nav nav-tabs">
        <li class="active"><a href="#serve_3" data-toggle="tab">Online Serving</a></li>
    </ul>
    <div class="tab-content">
        <div class="tab-pane active" id="serve_3">
            <div class="code" style="text-align: left;">
    <pre class="prettyprint lang-shell"><code>
$ curl -X POST http://localhost:8728/v1/infer -H "Content-Type: application/json" \
        -d '{
          "sepallength": 5.1,
          "sepalwidth": 3.5,
          "petallength": 1.4,
          "petalwidth": 0.2
        }'
{"class":0,"probability":[0.9599,0.0207,0.0194]}
  </code></pre>
            </div>
        </div>
    </div>

    <p>To infer on multiple samples, simply provides JSON array or JSON Lines (JSONL)
        in the request body. CSV is also supported.</p>

    <ul class="nav nav-tabs">
        <li class="active"><a href="#serve_4" data-toggle="tab">Online Serving</a></li>
    </ul>
    <div class="tab-content">
        <div class="tab-pane active" id="serve_4">
            <div class="code" style="text-align: left;">
    <pre class="prettyprint lang-shell"><code>
$ curl -X POST http://localhost:8728/v1/infer -H "Content-Type: application/json" \
        -d '{"sepallength": 5.1, "sepalwidth": 3.5, "petallength": 1.4,"petalwidth": 0.2}
          {"sepallength": 6.3, "sepalwidth": 3.3, "petallength": 6.0,"petalwidth": 2.5}'
{"class":0,"probability":[0.9599,0.0207,0.0194]}
{"class":2,"probability":[0.0259,0.0517,0.9224]}
  </code></pre>
            </div>
        </div>
    </div>

    <p>In fact, Smile serving endpoint is an end-to-end streaming API
        which applies back pressure throughout the entire stack. It can process the
        request body (e.g., a JSON array or CSV stream) on an element-by-element basis,
        and render the response immediately without waiting for the rest inference
        to complete first. Therefore, it is safe to send very large requests (multi-GB) to
        the endpoint! In the below example, we generate a dataset with 150,000 samples
        by repeating Iris data 1000 times. It takes only 7 seconds to finish the end-to-end
        processing including HTTP request and printing.</p>

    <ul class="nav nav-tabs">
        <li class="active"><a href="#serve_5" data-toggle="tab">Online Serving with Streaming</a></li>
    </ul>
    <div class="tab-content">
        <div class="tab-pane active" id="serve_5">
            <div class="code" style="text-align: left;">
    <pre class="prettyprint lang-shell"><code style="white-space: preserve nowrap;">
$ for i in {1..1000}; do tail -n 153 data/weka/iris.arff | head -n 150 >> iris.txt; done
$ cat iris.txt | curl -H "Content-Type: text/csv" -X POST --data-binary @- http://localhost:8728/v1/infer?format=csv
  </code></pre>
            </div>
        </div>
    </div>

    <p>By default, SmileServe binds at localhost:8728. If you prefer a different port and/or
        want to expose the server to other hosts, you may set the binding interface and port
        with <code>--host=0.0.0.0</code> and <code>--port=8000</code>, for example.</p>

    <h2 id="notebook">Notebooks</h2>

    <p>You can also use Smile in your favorite Notebook.
        We recommend JupyterLab and provide <code>jupyterlab.sh</code>
        to setup the conda environment of Jupyter Lab for Smile with
        kernels for Scala and Kotlin. When you run
        <code>jupyterlab.sh</code> the first time, it will set up the environment
        automatically. You can update the environment with the option
        <code>--update</code> later when needed.
    </p>

    <p>In Scala notebooks, it is helpful to add the following
        code to the notebook. We provide many notebook examples in
        the <code>notebooks</code> directory.</p>

    <ul class="nav nav-tabs">
        <li class="active"><a href="#notebook_1" data-toggle="tab">Scala</a></li>
    </ul>
    <div class="tab-content">
        <div class="tab-pane active" id="notebook_1">
            <div class="code" style="text-align: left;">
    <pre class="prettyprint lang-scala"><code style="white-space: preserve nowrap;">
    import $ivy.`com.github.haifengl::smile-scala:5.0.1`

    import scala.language.postfixOps
    import org.apache.commons.csv.CSVFormat
    import smile._
    import smile.util._
    import smile.math._
    import smile.math.MathEx.{log2, logistic, factorial, lfactorial, choose, lchoose, random, randomInt, permutate, c, cbind, rbind, sum, mean, median, q1, q3, `var` => variance, sd, mad, min, max, whichMin, whichMax, unique, dot, distance, pdist, KullbackLeiblerDivergence => kld, JensenShannonDivergence => jsd, cov, cor, spearman, kendall, norm, norm1, norm2, normInf, standardize, normalize, scale, unitize, unitize1, unitize2, root}
    import smile.math.distance._
    import smile.math.kernel._
    import smile.math.matrix._
    import smile.math.matrix.Matrix._
    import smile.math.rbf._
    import smile.stat.distribution._
    import smile.data._
    import smile.data.formula._
    import smile.data.measure._
    import smile.data.`type`._
    import smile.json._
    import smile.interpolation._
    import smile.validation._
    import smile.association._
    import smile.base.cart.SplitRule
    import smile.base.mlp._
    import smile.base.rbf.RBF
    import smile.classification._
    import smile.regression.{ols, ridge, lasso, svr, gpr}
    import smile.feature._
    import smile.clustering._
    import smile.vq._
    import smile.manifold._
    import smile.mds._
    import smile.sequence._
    import smile.projection._
    import smile.nlp._
    import smile.wavelet._
    </code></pre>
            </div>
        </div>
    </div>

    <p>To plot data with Swing based functions in Notebook, run the below code first.</p>

    <ul class="nav nav-tabs">
        <li class="active"><a href="#notebook_2" data-toggle="tab">Scala</a></li>
    </ul>
    <div class="tab-content">
        <div class="tab-pane active" id="notebook_2">
            <div class="code" style="text-align: left;">
    <pre class="prettyprint lang-scala"><code>
    import smile.plot.swing._
    import smile.plot.show
    import smile.plot.Render._
    </code></pre>
            </div>
        </div>
    </div>

    <p>To use Vega based plot functions in Notebook, run the below code instead.</p>

    <ul class="nav nav-tabs">
        <li class="active"><a href="#notebook_3" data-toggle="tab">Scala</a></li>
    </ul>
    <div class="tab-content">
        <div class="tab-pane active" id="notebook_3">
            <div class="code" style="text-align: left;">
    <pre class="prettyprint lang-scala"><code>
    import smile.plot.vega._
    import smile.plot.show
    import smile.plot.Render._
    </code></pre>
            </div>
        </div>
    </div>

    <h2 id="tutorial">A Gentle Example</h2>

    <p>This example shows how to use Smile for predictive modeling
        from Java and Scala code. First, let's load the data.
        Smile provides a couple of parsers for popular data formats,
        such as Parquet, Avro, Arrow, SAS7BDAT, Weka's ARFF files, LibSVM's
        file format, delimited text files, JSON, and binary sparse data.
        These classes are in the package <code>smile.io</code>. In the
        following example, we use the ARFF parser to load the weather dataset:</p>

    <ul class="nav nav-tabs">
        <li class="active"><a href="#java_2" data-toggle="tab">Java</a></li>
        <li><a href="#scala_2" data-toggle="tab">Scala</a></li>
    </ul>
    <div class="tab-content">
        <div class="tab-pane active" id="java_2">
            <div class="code" style="text-align: left;">
                <pre class="prettyprint lang-java"><code>
    import smile.io.*;
    var weather = Read.arff("data/weka/weather.nominal.arff");
          </code></pre>
            </div>
        </div>
        <div class="tab-pane" id="scala_2">
            <div class="code" style="text-align: left;">
                <pre class="prettyprint lang-scala"><code>
    import smile.io._
    val weather = read.arff("data/weka/weather.nominal.arff")
    </code></pre>
            </div>
        </div>
    </div>

    <p>Most Smile data parsers return a <a href="api/java/smile/data/DataFrame.html">DataFrame</a>
        object, which contain a number of named columns.
        We can also parse plain delimited text files and the parser automatically
        infer the schema. In the below, we load the USPS zip code handwriting
        dataset in a white space delimitered text file.</p>

    <ul class="nav nav-tabs">
        <li class="active"><a href="#java_3" data-toggle="tab">Java</a></li>
        <li><a href="#scala_3" data-toggle="tab">Scala</a></li>
    </ul>
    <div class="tab-content">
        <div class="tab-pane active" id="java_3">
            <div class="code" style="text-align: left;">
                <pre class="prettyprint lang-java"><code>
    import org.apache.commons.csv.CSVFormat;

    var format = CSVFormat.DEFAULT.withDelimiter(' ');
    var zipTrain = Read.csv("data/usps/zip.train", format);
    var zipTest = Read.csv("data/usps/zip.test", format);
          </code></pre>
            </div>
        </div>
        <div class="tab-pane" id="scala_3">
            <div class="code" style="text-align: left;">
                <pre class="prettyprint lang-scala"><code>
    val zipTrain = read.csv("data/usps/zip.train", delimiter = " ", header = false)
    val zipTest = read.csv("data/usps/zip.test", delimiter = " ", header = false)
    </code></pre>
            </div>
        </div>
    </div>

    <p>Because this data doesn't have a header line, the parser will assign
        V1, V2, ... as the column names. In particular, the first column
        (V1) is the class label. </p>

    <p>Smile implements a variety of classification and regression algorithms.
        In what follows, we train a random forest model on the USPS data.
        Random forest is an ensemble classifier that consists of many decision
        trees and outputs the majority vote of individual trees.
        The method combines bagging idea and the random selection of features.</p>

    <ul class="nav nav-tabs">
        <li class="active"><a href="#java_4" data-toggle="tab">Java</a></li>
        <li><a href="#scala_4" data-toggle="tab">Scala</a></li>
    </ul>
    <div class="tab-content">
        <div class="tab-pane active" id="java_4">
            <div class="code" style="text-align: left;">
                <pre class="prettyprint lang-java"><code>
    import smile.classification.*;
    import smile.data.formula.Formula;

    var formula = Formula.lhs("V1");
    
    var prop = new java.util.Properties();
    prop.setProperty("smile.random.forest.trees", "200");
    var forest = RandomForest.fit(formula, zipTrain, prop);
    System.out.println(forest.metrics());
          </code></pre>
            </div>
        </div>
        <div class="tab-pane" id="scala_4">
            <div class="code" style="text-align: left;">
                <pre class="prettyprint lang-scala"><code>
    val formula: Formula = "V1" ~ "."

    val forest = randomForest(formula, zipTrain, ntrees = 200)
    println(forest.metrics())
    </code></pre>
            </div>
        </div>
    </div>

    <p>In the example, we firstly define a <code>Formula</code> object, which
        specifies the model in a symbolic way. The left-hand-side (LHS) of
        formula is the response variable, and the right-hand-side (RHS) is
        a list of terms as independent variables. When the RHS is not specified,
        the rest of columns in the data frame are used by default. In the
        simpliest case, the terms (both of LHS and of RHS) are column
        names. But they can be functions (e.g. log) and transformations
        (e.g. interaction and factor crossing) too. The functions/transformations
        are symbolic and thus lazy.</p>

    <p>With random forest, we may estimate the model accuracy with out-of-bag
        (OOB) samples. This is useful especially when we don't have a separate
        test dataset.</p>

    <p>Now let's train a support vector machine (SVM) on the USPS data. As SVM
        is a kernel learning machine, it can be applied on any type of data
        as long as we can define a Mercer kernel on the data. Therefore,
        SVM class doesn't take a DataFrame as input but a generic array.
        We can leverage the formula object to extract the training samples
        and labels.</p>

    <ul class="nav nav-tabs">
        <li class="active"><a href="#java_5" data-toggle="tab">Java</a></li>
        <li><a href="#scala_5" data-toggle="tab">Scala</a></li>
    </ul>
    <div class="tab-content">
        <div class="tab-pane active" id="java_5">
            <div class="code" style="text-align: left;">
                <pre class="prettyprint lang-java"><code>
    var x = formula.x(zipTrain).toArray();
    var y = formula.y(zipTrain).toIntArray();
    var testx = formula.x(zipTest).toArray();
    var testy = formula.y(zipTest).toIntArray();
          </code></pre>
            </div>
        </div>
        <div class="tab-pane" id="scala_5">
            <div class="code" style="text-align: left;">
                <pre class="prettyprint lang-scala"><code>
    val x = formula.x(zipTrain).toArray()
    val y = formula.y(zipTrain).toIntArray()
    val testx = formula.x(zipTest).toArray()
    val testy = formula.y(zipTest).toIntArray()
    </code></pre>
            </div>
        </div>
    </div>

    <p>The SVM employs a Gaussian kernel and one-to-one strategy
        as this is a multi-class problem. We also evaluate the model
        on the test data with <code>Validation</code> class, which
        provides a variety of model validation methods such as
        cross validation, bootstrap, etc.</p>

    <ul class="nav nav-tabs">
        <li class="active"><a href="#java_6" data-toggle="tab">Java</a></li>
        <li><a href="#scala_6" data-toggle="tab">Scala</a></li>
    </ul>
    <div class="tab-content">
        <div class="tab-pane active" id="java_6">
            <div class="code" style="text-align: left;">
                <pre class="prettyprint lang-java"><code>
    import smile.math.kernel.GaussianKernel;
    import smile.validation.*;

    var kernel = new GaussianKernel(8.0);
    var svm = OneVersusOne.fit(x, y, (x, y) -> SVM.fit(x, y, kernel, 5, 1E-3));
    var pred = svm.predict(testx);
    System.out.format("Accuracy = %.2f%%%n", (100.0 * Accuracy.of(testy, pred)));
    System.out.format("Confusion Matrix: %s%n", ConfusionMatrix.of(testy, pred));
          </code></pre>
            </div>
        </div>
        <div class="tab-pane" id="scala_6">
            <div class="code" style="text-align: left;">
                <pre class="prettyprint lang-scala"><code>
    val kernel = new GaussianKernel(8.0)
    val svm = ovo(x, y) { (x, y) =>
      SVM.fit(x, y, kernel, 5, 1E-3)
    }
    </code></pre>
            </div>
        </div>
    </div>

    <p>Lastly, we will train a 5-layer deep learning model. Deep learning
        requires the features properly scaled/standardized. In this example,
        we employ the class <code>Standardizer</code> to transforms features
        to 0 mean and unit variance. An alternative is to subtract the median
        and divide by the IQR, which is implemented <code>RobustStandardizer</code>.</p>

    <ul class="nav nav-tabs">
        <li class="active"><a href="#java_7" data-toggle="tab">Java</a></li>
        <li><a href="#scala_7" data-toggle="tab">Scala</a></li>
    </ul>
    <div class="tab-content">
        <div class="tab-pane active" id="java_7">
            <div class="code" style="text-align: left;">
                <pre class="prettyprint lang-java"><code>
    import smile.base.mlp.Layer;
    import smile.base.mlp.OutputFunction;
    import smile.classification.MLP;
    import smile.math.MathEx;
    
    var net = new MLP(Layer.input(256),
      Layer.sigmoid(768),
      Layer.sigmoid(192),
      Layer.sigmoid(30),
      Layer.mle(10, OutputFunction.SIGMOID)
    );

    net.setLearningRate(TimeFunction.linear(0.01, 20000, 0.001));
    
    for (int epoch = 0; epoch < 10; epoch++) {
      System.out.format("----- epoch %d -----%n", epoch);
      for (int i : MathEx.permutate(x.length)) {
        net.update(x[i], y[i]);
      }
      var prediction = net.predict(testx);
      System.out.format("Accuracy = %.2f%%%n", (100.0 * Accuracy.of(testy, prediction)));
    }
          </code></pre>
            </div>
        </div>
        <div class="tab-pane" id="scala_7">
            <div class="code" style="text-align: left;">
                <pre class="prettyprint lang-scala"><code>
    val net = new MLP(Layer.input(256),
      Layer.sigmoid(768),
      Layer.sigmoid(192),
      Layer.sigmoid(30),
      Layer.mle(10, OutputFunction.SIGMOID)
    )

    net.setLearningRate(TimeFunction.linear(0.01, 20000, 0.001));
    
    (0 until 10).foreach(epoch => {
      println("----- epoch %d -----" format epoch)
      MathEx.permutate(x.length).foreach(i =>
        net.update(x(i), y(i))
      )
      val prediction = net.predict(testx)
      println("Accuracy = %.2f%%" format (100.0 * Accuracy.of(testy, prediction)))
    })
    </code></pre>
            </div>
        </div>
    </div>

    <p>To use the trained model, we can apply the method <code>predict</code>
        on a new sample. Besides just returning class label, many methods
        (e.g. neural networks) can also output the posteriori probabilities
        of each class.</p>

    <ul class="nav nav-tabs">
        <li class="active"><a href="#java_8" data-toggle="tab">Java</a></li>
        <li><a href="#scala_8" data-toggle="tab">Scala</a></li>
    </ul>
    <div class="tab-content">
        <div class="tab-pane active" id="java_8">
            <div class="code" style="text-align: left;">
                <pre class="prettyprint lang-java"><code>
    var posteriori = new double[10];
    forest.predict(zipTest.get(0), posteriori);
    svm.predict(testx[0]);
    net.predict(testx[0], posteriori);
          </code></pre>
            </div>
        </div>
        <div class="tab-pane" id="scala_8">
            <div class="code" style="text-align: left;">
                <pre class="prettyprint lang-scala"><code>
    val posteriori = new Array[Double](10)
    forest.predict(zipTest.get(0), posteriori)
    svm.predict(testx(0))
    net.predict(testx(0), posteriori)
    </code></pre>
            </div>
        </div>
    </div>

    <div id="btnv">
        <a class="btn-next-text" href="overview.html" title="Next Section: What's Machine Learning"><span>What's Machine
                Learning</span></a>
        <span class="btn-arrow-right">&nbsp;&rarr;</span>
    </div>
</div>

<script type="text/javascript">
    $('#toc').toc({ exclude: 'h1, h5, h6', context: '', autoId: true, numerate: false });
</script>
